package com.yn.xgame;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;


/**
 * NettyProtobufHandler
 * Created by wangboo on 17/7/11.
 */
public class NettyProtobufHandler implements ChannelInboundHandler {

    public interface Callback {
        void handle(ChannelHandlerContext ctx, byte[] bin);
        void channelUnregistered(ChannelHandlerContext ctx);
    }

    private Callback callback;
    private CtxManager ctxManager;

    public NettyProtobufHandler(Callback callback) {
        this.callback = callback;
        this.ctxManager = new CtxManager();
    }

    private static final Logger logger = LoggerFactory.getLogger(NettyProtobufHandler.class);

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelRegistered");
        ctxManager.add(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelUnregistered");
        callback.channelUnregistered(ctx);
        ctxManager.remove(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelActive");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelInactive");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        if (logger.isDebugEnabled()) {
            byteBuf.markReaderIndex();
            int allLen = byteBuf.capacity();
            byte[] allBin = new byte[allLen];
            byteBuf.readBytes(allBin);
            byteBuf.resetReaderIndex();
            logger.debug("recv bin: {}", allBin);
        }
        logger.debug("recv: {}", msg);
        int len = byteBuf.capacity()-1;
        byte mask = byteBuf.readByte();
//        byte serialNo = (byte) (mask | 0x7f);
//        byte isZip = (byte) (mask & 0x10);
//        Attribute<Byte> byteVal = ctx.attr(serialNoKey);
//        Byte preSerial = byteVal.get();
        byte[] bin = new byte[len];
        byteBuf.readBytes(bin, 0, len);
//        if(preSerial != null && preSerial.equals(serialNo)) {
//            logger.warn("repeat attack, skip this req, bin: ", Arrays.toString(byteBuf.array()));
//            return;
//        }
//        if (isZip == 0x10) {
//            logger.error("req is zipped, not support yet, bin: ", Arrays.toString(byteBuf.array()));
//            return;
//        }
        callback.handle(ctx, bin);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelReadComplete");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        logger.debug("userEventTriggered evt: {}", evt);
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        logger.debug("channelWritabilityChanged");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        logger.debug("handlerAdded");
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        logger.debug("handlerRemoved");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("exceptionCaught: ", cause);
    }

    public CtxManager getCtxManager() {
        return ctxManager;
    }
}
